Skip to content

fix(docx): name timeline rails once and correct the ledger's fates - #950

Merged
DemchaAV merged 2 commits into
2.5-devfrom
fix/docx-report-ledger-truth
Oct 23, 2026
Merged

DemchaAV merged 2 commits into
2.5-devfrom
fix/docx-report-ledger-truth

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Why

The DOCX export's report and its field ledger are the contract for what an export loses. Read against the code, a few of their statements were not true.

  • A note twice. The timeline rail note was added once per layout pass fragment. Every rail shares the path @timeline-rail, so each timeline, and each page a rail runs onto, added the same note again. cv-terracotta_rail, with two timelines, carried it twice.
  • WRITTEN, or a narrower case, for fields a path loses. DocxNodeFieldLedgerTest said these were written, though the report names their loss:
    • the geometry and paint of a drawing the export drops, which a note names. Among its reasons: no layout, a page zone, a gradient alone or nothing painted, a page no paragraph is written on;
    • with no layout, a paragraph's line spacing and a section's or a line's keeps;
    • a paragraph's line spacing in a page zone, where the zone's note says where its part stands;
    • keeps inside a panel the layout runs on to the next page (reportAKeepThePanelBreaks), and keeps composed in a table cell, where the table row is what is kept;
    • a page field's kind, style, padding and margin anywhere but on a page zone's line, where it is dropped.
  • A page field's alignment. The ledger called it INERT, and TextAlign's centre and right "not applied" to a page field. PageFieldDefinition sets the field in a box a point wider than its number, so its alignment moves the number by up to that point. The capability matrix and the DOCX recipe said the same.
  • Two losses no note names, stated as written:
    • A stand-in spacer. DocxLayerColumns takes a spacer level with another layer's content, in a band or a stack written as columns, as a stand-in. Where that content is not written in its place, the spacer is not written.
    • A paragraph composed in a table cell whose text no laid-out line carries. It gets no line gap (DocxLayoutMetrics.lineGap).
  • A stale CHANGELOG bullet. A v2.5.0 entry still said a band opening with a list or a row loses the space above it. A later entry in the same section fixed that.

What changed

  • DocxSemanticBackend: the rail note is added once per path per section.
    • Every fragment is still queued before the name is checked.
    • DocxDrawingAnchors.Owner("timeline rail", path) already reckons what no paragraph carries for all rails of that path together. One note now matches that one reckoning.
  • DocxNodeFieldLedgerTest: the fates above name the path where the field is lost.
    • DRAWING_DROPPED for drawings, also inside RULE_WIDTH and RULE_TRANSLUCENCY;
    • KEEP for section and line keeps;
    • FIELD_OUTSIDE_A_ZONE for page fields;
    • two new gaps among the known cases: STAND_IN_LEFT_EMPTY on SpacerNode.height and LINE_GAP_UNREAD on ParagraphNode.lineSpacing.
  • DocxValueFieldLedgerTest: TextAlign.CENTER/RIGHT drop "a page field's the page does not apply" and name a page field off a zone's line.
  • Docs:
    • the capability matrix's page-zone row and the recipe's page-field sentence are corrected;
    • the stale CHANGELOG bullet now points to the entry that holds the space;
    • new CHANGELOG entries under Public API (the rail note) and Tests (the ledger).
  • Not in this change: writing the stand-in spacer and the composed paragraph's line gap. This change only states them.

Verification

  • DocxFlowContainerReportTest.twoTimelinesRailsAreNamedOnce (new). Two timelines with connectors give exactly one timeline rail note, and twice the anchored drawings of one timeline: both rails and their markers are drawn.
  • Fail-closed: 5 sabotages, each run alone, all caught.
    • The rail named for every fragment again: the new test fails.
    • The stand-in gap removed from the known cases: the node ledger fails.
    • The unread line gap removed from the known cases: the node ledger fails.
    • A paragraph's line spacing left without an entry: the node ledger fails.
    • A TextAlign constant left without an entry: the value ledger fails.
  • Corpus:
    • The 62 DOCX files are byte for byte the same.
    • The notes go from 1385 to 1384. The only note gone is cv-terracotta_rail's second timeline rail note.
  • Gate:
    • ./mvnw -B -ntp clean verify -pl <core, render-pdf, render-docx, render-pptx, templates, testing, qa, coverage> -am → BUILD SUCCESS. Core 821, render-pdf 339, render-docx 2088, testing 5, render-pptx 142, templates 127, qa 1828.
    • The JDK 17 knowledge checks pass, and core javadoc has 0 warnings.
    • ./mvnw -f examples/pom.xml test → BUILD SUCCESS, 93 tests.
  • After the last ledger, test and wording fixes (the test ledger and the docs only; the backend is unchanged since the gate):
    • ./mvnw verify -pl :graph-compose-render-docx → BUILD SUCCESS, 2088 tests;
    • the qa documentation guards → 28 tests, BUILD SUCCESS;
    • the claims, routes and stability checks pass.

Lane: shared-engine (render-docx): the report and the test ledger only. No public API change, and no change to the written DOCX.

- Every rail the layout draws shares one path, so each timeline, and
  each page a rail runs onto, named it again, word for word:
  cv-terracotta_rail carried the note twice. The rail is named once a
  path a section; what no paragraph carries is reckoned for all of them
  together, as before.
- The field ledger stated WRITTEN, or a narrower case, for fields a
  path loses and the report names: the geometry and paint of a drawing
  the export drops (no layout, a gradient alone, nothing painted); a
  paragraph's line spacing and a section's or a line's keeps with no
  layout; keeps inside a panel the layout runs on; a page field's kind,
  style, padding and margin in the flow.
- A page field's alignment moves its number up to a point in its box;
  the ledger, the capability matrix and the DOCX recipe said it moved
  nothing.
- Two losses no note names are gaps now: a spacer level with another
  layer's content in a band or a stack written as columns, where that
  content is not written in its place; and a paragraph composed in a
  table cell whose text no laid-out line carries, written with no line
  gap.
- A v2.5.0 CHANGELOG bullet still said a band opening with a list or a
  row loses the space above it, which a later change fixed.
@DemchaAV
DemchaAV marked this pull request as draft October 23, 2026 13:56
…elds take

- A drawing the export drops is named by a note for every reason it
  has, a page zone and a page no paragraph is written on among them,
  not only with no layout, a gradient alone or nothing painted.
- A page field is dropped anywhere but on a page zone's line, a table
  cell or a layer's column as much as the body.
- A paragraph's line spacing in a page zone is where the zone's note
  places its part; a keep composed in a table cell is the row's.
- The CHANGELOG says a line or a shape written as a rule is written as
  a rule, not that it keeps its geometry and paint.
@DemchaAV
DemchaAV marked this pull request as ready for review October 23, 2026 14:03
@DemchaAV
DemchaAV merged commit 3e4776a into 2.5-dev Oct 23, 2026
13 checks passed
@DemchaAV
DemchaAV deleted the fix/docx-report-ledger-truth branch October 23, 2026 14:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant